package AIEngine;

import java.util.Random;

/**
 * The AIPlayer class implements all methods that are used 
 * to assess the next move.
 *
 * @see Player#request( Move opponentMove )
 * @see Player#confirm( Status boardStatus )
 */
import GameEngine.*;

/**
 *
 * @author S.Herzog
 */
@SuppressWarnings("unused")
public class AIPlayer implements Player {

	AIEngine test;
	Board board = new Board();
	int[] rot = new int[2];
	int algType;
	/**
	 *
	 */
	public int[][] basic = {
			{0, 0, 0, 0, 0, 0},
			{0, 0, 0, 0, 0, 0},
			{0, 0, 0, 0, 0, 0},
			{0, 0, 0, 0, 0, 0},
			{0, 0, 0, 0, 0, 0},
			{0, 0, 0, 0, 0, 0}};
	/**
	 *
	 */
	public int[][] tmpBoard = new int[6][6];
	private boolean black;
	private String color;
	private Move lastMove = null;
	private boolean isFirstMove = true;

	/**
	 * The default constructor for a aiplayer
	 *
	 * @param black shows if the player is first or second
	 * @throws Exception 
	 */
	public AIPlayer(boolean black,int algType,int iaLevel)  {
		this.black = black;
		this.color = this.black ? "black" : "red";
		System.out.println("Player " + this.color + " comes up!");
		this.algType=algType; 

		/*switch the algorithm to use*/        
		if(algType < 0 || algType > 4){ System.out.println("Algorithm error"); }
		else{
			switch(algType){
			case 0:
				test = new MinMaxEngine(black,iaLevel);
				break;
			case 1:
				test = new AlphaBetaEngine(black,iaLevel);
				break;
			case 2:
				test = new HeuristicEngine(black);
				break;
			case 3:
				test = new MinMaxRandomEngine(black,iaLevel);
				break;
			case 4:
				test = new AlphaBetaRandomEngine(black,iaLevel);
				break;
			default:
				test = null;
			}
		} 

	}
	/**
	 * This method handles the interaction between the
	 * player and the playing field.
	 *
	 * @param opponentMove The last move of the opponent player.
	 * @return Returns An object that represents the current move.
	 */
	public Move request(Move opponentMove, int turnsLeft){

		int mov[] = {-1, -1, 1, 1};
		Move move = null;
		boolean clockwise;


		if (opponentMove != null) {
			System.out.println("Got opponent move (" + opponentMove + "). ");
			if (board.getStatus().value() == Status.GAME_ON) {
				System.out.println("Opponent move:");
				setter(opponentMove, false);
			}
		}


		if(isFirstMove){
			move = getFirstMove();
			isFirstMove = false;
		}else{
			Node parent = new Node(null, basic, turnsLeft);
			parent.setCamp(black);

			Node result = test.getBestMove(parent);

			System.out.println("------Si minimax----------");
			for(int i=0; i<6; i++){
				for(int j=0; j<6; j++){
					System.out.print("[" + result.getBoard()[i][j] + "]");
				}
				System.out.println("");
			}

			System.out.println("----------------------");

			clockwise = (result.getMove()[3] > 0) ? true : false;
			move = new GameEngine.Move(this.black, result.getMove()[1] + 1, result.getMove()[0] + 1, result.getMove()[2], clockwise);
		}


		if (board.getStatus().value() == Status.GAME_ON) {
			System.out.println("Your move:");
			setter(move, true);
		}
		this.lastMove = move;
		return move;
	}

	
	/**
	 * Checks if an error occured or if an move was illegal.
	 *
	 * @param boardStatus Information of the last move.
	 */
	public void confirm(Status boardStatus) throws Exception{

		if (boardStatus.value() == Status.ILLEGAL_MOVE) {       // checks if last move is valid
			throw new Exception("Illegal move!");
		}

		if (boardStatus.value() == Status.ERROR) {             //checks if an error occurred
			throw new Exception("Error occurred!");
		}
		if (boardStatus.value() == Status.BLACK_WINS) {         // checks if black wins
			System.out.println("Black (@) wins!");

		}
		if (boardStatus.value() == Status.WHITE_WINS) {         // checks if red wins
			System.out.println("Red (#) wins!");
		}
		if (boardStatus.value() == Status.DRAW) {           // checks if a draw occurres
			System.out.println("Draw!");
		}
	}

	/**
	 * The setter is supposed to set every move his own aiboard.
	 *
	 * @param move Moveobjekt conatains the colum, row, quadrant and the direction of rotation
	 * @param black represents the playerside
	 */
	public void setter(Move move, boolean black) {
		int ver, hor, quad;
		ver = move.column();
		hor = move.row();
		quad = move.element();
		board.setMarble(ver, hor, move.black());
		board.rotate(quad, move.clockwise());
		this.basic = board.getBoard();

	}
	
	@Override
	public void setAlgorithm(int algType1) {
		this.algType = algType1;
	}

	/**
	 * This method copys on cell from a array into an other,
	 *
	 * @param field
	 * @param tofillup
	 */
	public static void fill(int[][] field, int[][] tofillup) {
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 6; j++) {
				tofillup[i][j] = field[i][j];
			}
		}
	}

	public Move getFirstMove(){
		Move firstMove;
		Random random = new Random(System.nanoTime());
		int chosenMove;
		int row = -1;
		int column = -1;
		int quadrant = -1;
		boolean clockwise = true;

		chosenMove = random.nextInt(4);

		switch(chosenMove){
		case 0:
			row = 1;
			column = 1;
			quadrant = 1;
			break;
		case 1:
			row = 1;
			column = 4;
			quadrant = 2;
			clockwise = false;
			break;
		case 2:
			row = 4;
			column = 1;
			quadrant = 3;
			break;
		case 3:
			row = 4;
			column = 4;
			quadrant = 4;
			clockwise = false;
			break;
		}

		if(basic[row][column]!=0){
			boolean isModified = false;

			for(int i=0; i<6; i++){
				for(int j=0; j<6; j++){
					if(BasicAI.isEmpty(basic[i][j]) && !isModified){
						row = i;
						column = j;
						isModified = true;
					}
				}
			}
		}

		firstMove = new GameEngine.Move(this.black, column+1, row+1, quadrant, clockwise);

		return firstMove;
	}
}

